﻿// FixTtxt.cpp: implementation of the CFixTtxt class.
//
//////////////////////////////////////////////////////////////////////

#include "stdafx.h"
#include "iTrans.h"
#include "FixTtxt.h"
#include "ConvISO8859_1.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif

//////////////////////////////////////////////////////////////////////
// Construction/Destruction
//////////////////////////////////////////////////////////////////////

CFixTtxt::CFixTtxt() {}

CFixTtxt::~CFixTtxt() {}

int CFixTtxt::iFind(char *chSrc, int iSize, char *chStr, int iStart)
{
	int iLen = strlen(chStr);
	for (int i=iStart; i<=iSize-iLen; i++) {
		if (strncmp(chSrc+i, chStr, iLen) == 0) return i;
	}
	return -1;
}

bool CFixTtxt::bFixTtxt(LPCTSTR lpSrc, LPCTSTR lpDst, int iFontSize, int iVideoDuration)
{
	if (!CSmallUtilz4iTrans::IsFileorfolder(lpSrc))
		return false;

	if (!iFontSize) iFontSize=18;
	//fontSize="18"
	char cfontSize[20];
	sprintf_s(cfontSize, 20, "fontSize=\"%d\"", iFontSize);

	UINT iSize = CSmallUtilz4iTrans::GetFileSize(lpSrc);
	char *chSrc = new char[iSize+1];

	FILE *f;
	if (_tfopen_s(&f, lpSrc, _T("rb")) || !f) {
		delete []chSrc;
		return false;
	}
	fread(chSrc, sizeof(char), iSize, f);
	fclose(f);
	chSrc[iSize] = 0;

	if (!lpDst) lpDst = lpSrc;

	if (_tfopen_s(&f, lpDst, _T("wb")) || !f) {
		delete []chSrc;
		return false;
	}

	int iP = iFind(chSrc, iSize, "</TextStreamHeader>", 0);
	if (iP<0) {
		delete []chSrc;
		DeleteFile(lpDst);
		fclose(f);
		return false;
	}
	iP+=19;

	//fontSize 쓰기
	{
		//일부 변수 처리를 위해 블럭으로 묶음
		int iBegin = iFind(chSrc, iP, "fontSize=\"", 0);
		if (iBegin>0) {
			int iEnd = iFind(chSrc, iP, "\"", iBegin+10);
			if (iEnd>0) {
				fwrite(chSrc, sizeof(char), iBegin, f);
				fwrite(cfontSize, sizeof(char), strlen(cfontSize), f);
				fwrite(chSrc+iEnd+1, sizeof(char), iP-iEnd-1, f);
			} else {
				fwrite(chSrc, sizeof(char), iP, f);
			}
		} else {
			fwrite(chSrc, sizeof(char), iP, f);
		}
	}

	fwriteCRLF(f);

	///////////////////
	// 헤더 복제 완료
	///////////////////
	
	CString csOldTime = _T(" ");
	CString csMaxTime = _T("99:99:99.999");
	if (iVideoDuration>0) {
		int h, m, s, ms;
		ms = iVideoDuration % 1000;
		s = iVideoDuration / 1000;
		m = s / 60;
		s %= 60;
		h = m / 60;
		m %= 60;
		if (h<=99) {
			csMaxTime.Format(_T("%02d:%02d:%02d.%03d"), h, m, s, ms);
		}
	}

	while (true) {
		int iBegin = iFind(chSrc, iSize, "<TextSample sampleTime=\"", iP);
		if (iBegin<0) break;
		
		int iEnd = iFind(chSrc, iSize, "</TextSample>", iBegin+24);
		if (iEnd<0) break;
		iP = iEnd+13;

		CString csThisTime = _T("");
		//<TextSample sampleTime="00:00:00.000"
		//012345678901234567890123456789012345

		for (int ch=0; ch<12; ch++)
			csThisTime += chSrc[24+iBegin+ch];

		if (
			(csThisTime.Compare(csOldTime) <= 0) ||
			(csThisTime.Compare(csMaxTime) > 0)
			) continue;
		csOldTime = csThisTime;

		int i = iFind(chSrc, iSize, ">", iBegin+24);
		fwrite(chSrc+iBegin, sizeof(char), i-iBegin+1, f);

		FixIt(chSrc+i+1, iEnd-i-1, f, cfontSize);

		fwrite("</TextSample>", 1, 13, f);
		fwriteCRLF(f);
	}

	fwrite("</TextStream>", 1, 13, f);
	fwriteCRLF(f);

	delete []chSrc;
	fclose(f);

	return true;
}

bool CFixTtxt::bAdjustTime(LPCTSTR lpSrc, LPCTSTR lpDst, int iTimePlus)
{
	if (!CSmallUtilz4iTrans::IsFileorfolder(lpSrc))
		return false;

	UINT iSize = CSmallUtilz4iTrans::GetFileSize(lpSrc);
	char *chSrc = new char[iSize+1];

	FILE *f;
	if (_tfopen_s(&f, lpSrc, _T("rb")) || !f) {
		delete []chSrc;
		return false;
	}
	fread(chSrc, sizeof(char), iSize, f);
	fclose(f);
	chSrc[iSize] = 0;

	int H, M, S, MS;
	char chTime[15];	// 사실 13이어야 정상임

	if (!lpDst) lpDst = lpSrc;

	if (_tfopen_s(&f, lpDst, _T("wb")) || !f) {
		delete []chSrc;
		return false;
	}

	int iP = 0;
	while (true) {
		int iBegin = iFind(chSrc, iSize, "<TextSample sampleTime=\"", iP);
		if (iBegin<0) break;
		iBegin+=24;
		
		int iEnd = iFind(chSrc, iSize, "</TextSample>", iBegin);
		if (iEnd<0) break;
		iP = iEnd+13;

		int iTime = CSmallUtilz4iTrans::cTime2Int(chSrc+iBegin, true) + iTimePlus;
		CSmallUtilz4iTrans::ms2HMSMS(iTime, H, M, S, MS);
		sprintf_s(chTime, 15, "%02d:%02d:%02d.%03d", H, M, S, MS);

		memcpy(chSrc+iBegin, chTime, 12);
	}

	fwrite(chSrc, sizeof(char), iSize, f);
	fclose(f);

	delete []chSrc;

	return true;
}

TCHAR CFixTtxt::tcDecodeUnicode(char *ch, int &iDecodedLen)
{
	//일단 &를 보고 들어왔다
	//무조건 ;를 찾고 시작

	iDecodedLen=0;
	while (ch[iDecodedLen] && ch[iDecodedLen]!=';') iDecodedLen++;

	iDecodedLen++;

	if (ch[0]!='&') return 0;
	if (ch[1]=='#') {
		ch+=2;
		TCHAR tc=0;

		while (isdigit_char(*ch)) {
			tc = tc*10 + ((*ch)-'0');
			ch++;
		}

		return tc;
	} else {
		TCHAR ret;
		int len;
		return (CConvISO8859_1::convOne(ch, true, ret, len) && (ret < 128))?ret:_TCHAR(' ');
	}
}

TCHAR * CFixTtxt::tcDecode(char *ch, int iLen, int &iNewLen)
{
	if (!iLen) {
		iNewLen = 0;
		return NULL;
	}

	TCHAR *tc = new TCHAR[iLen];
	ZeroMemory(tc, iLen*sizeof(tc[0]));

	int i, iTemp;
	iNewLen=0;
	for (i=0; i<iLen; i++) {
		if (ch[i] == '<') break;

		switch (ch[i]) {
		case 0:
			// 이럴 리는 없지만...
			break;

		case '&':
			tc[iNewLen] = tcDecodeUnicode(ch+i, iTemp);
			i+=iTemp;
			i--;
			if (tc[iNewLen]) iNewLen++;
			continue;

		case 0x0d:
		case 0x0a:
			tc[iNewLen++] = 0x0a;
			i++;
			break;

		default:
			tc[iNewLen++] = ch[i];
		}
	}

	return tc;
}

void CFixTtxt::ApplyEffect(char *chEffect, int iLen, char *chTag, int iTagLen)
{
	//<Style fromChar="0" toChar="17" styles="Bold " fontID="1" fontSize="18" color="ff ff ff ff"/>
	char *ch = chGetValue(chTag, iTagLen, "fromChar");
	if (!ch) return;
	int fromChar = atoi(ch);
	delete ch;

	ch = chGetValue(chTag, iTagLen, "toChar");
	if (!ch) return;
	int toChar = atoi(ch);
	delete ch;

	if (toChar>iLen) toChar = iLen;

	ch = chGetValue(chTag, iTagLen, "styles");
	if (ch) {
		int iLenCh = strlen(ch);

		bool bBold = (iFind(ch, iLenCh, "Bold", 0)>=0);
		bool bItalic = (iFind(ch, iLenCh, "Ital", 0)>=0);
		bool bUnderlined = (iFind(ch, iLenCh, "Unde", 0)>=0);

		for (int i=fromChar; i<toChar; i++) {
			if (bBold) chEffect[i*12] = 'B';
			if (bItalic) chEffect[i*12+1] = 'I';
			if (bUnderlined) chEffect[i*12+2] = 'U';
		}

		delete ch;
	}

	ch = chGetValue(chTag, iTagLen, "color");
	if (ch) {
		int iLenCh = strlen(ch);

		// 8은 매직넘버인데, 그냥 그러려니...
		char *colortemp = new char[(iLenCh+1)*8];
		// ff ff ff ff
		// 01234567890
		// ideal하게 저장하려면 12바이트가 소요됨
		// 그냥 포맷 확인하면서 ffffffff 형식으로 변환
		// 즉, 8chars이면 저장, 아니면 버림
		
		ZeroMemory(colortemp, (iLenCh+1)*8);
		
		int pos=0;
		for (int i=0; (i<iLenCh) && (pos<11);) {
			if (isxdigit_char(ch[i])) {
				if (isxdigit_char(ch[i+1])) {
					colortemp[pos] = ch[i];
					colortemp[pos+1] = ch[i+1];
					pos+=2;
					i+=2;
				} else {
					colortemp[pos] = '0';
					colortemp[pos+1] = ch[i];
					pos+=2;
					i+=1;
				}
			}
			if (ch[i]==' ') {
				while (ch[i] == ' ') i++;
			} else {
				break;
			}
		}
		if (strlen(colortemp) == 8) {
			for (int j=fromChar; j<toChar; j++) {
				memcpy(chEffect+(j*12+3), colortemp, 8);
			}
		}
		
		delete []colortemp;
		delete ch;
	}
}

char * CFixTtxt::chGetValue(char *chTag, int iLen, char *chElement)
{
	int i = strlen(chElement);
	char *ch = new char[i+3];
	strcpy_s(ch, i+3, chElement);
	ch[i] = '=';
	ch[i+1] = '\"';
	ch[i+2] = 0;

	int j = iFind(chTag, iLen, ch, 0);
	if (j<0) {
		delete []ch;
		return NULL;
	}

	j+=(i+2);
	// 결과값은 j에서 시작함
	// 따옴표까지 찾음

	int k = iFind(chTag, iLen, "\"", j);
	if (k<0) {
		delete []ch;
		return NULL;
	}

	delete []ch;

	ch = new char[k-j+1];

	strncpy_s(ch, k-j+1, chTag+j, k-j);
	ch[k-j] = 0;

	return ch;
}

void CFixTtxt::WriteXMLStr(FILE *f, TCHAR *tc, int iLen)
{
	static char quot[] = "&quot;";
	static char amp[] = "&amp;";
	static char apos[] = "&apos;";
	static char lt[] = "&lt;";
	static char gt[] = "&gt;";
	static char xmlch[10];

	for (int i=0; i<iLen; i++) {
		switch (tc[i]) {
		case _TCHAR(0x0d):
		case _TCHAR(0x0a):
			fwriteCRLF(f);
			break;

		case _TCHAR('\"'):
			fwrite(quot, 1, 6, f);
			break;

		case _TCHAR('&'):
			fwrite(amp, 1, 5, f);
			break;

		case _TCHAR('\''):
			fwrite(apos, 1, 6, f);
			break;

		case _TCHAR('<'):
			fwrite(lt, 1, 4, f);
			break;

		case _TCHAR('>'):
			fwrite(gt, 1, 4, f);
			break;

		default:
			if (tc[i]>0 && tc[i]<127)
				fwrite(tc+i, 1, 1, f);
			else {
				int iL = sprintf_s(xmlch, 10, "&#%u;", tc[i]);
				fwrite(xmlch, 1, iL, f);
			}
		}
	}
}

void CFixTtxt::Write1Style(FILE *f, int iFrom, int iTo, char *Style, char *cfontSize)
{
	//BIUff00ffff(NULL) 형태의 12바이트
	//<Style fromChar="0" toChar="17" styles="Bold " fontID="1" fontSize="18" color="ff ff ff ff"/>

	//Bold Italic Underlined
	//0123456789012345678901 (22)

	//xxxffffff

	//기본형은 굳이 작성할 필요 없음
	if (strcmp(Style, "xxxffffffff") == 0) return;
	fwrite("<Style fromChar=\"", 1, 17, f);

	static char values[100];
	int iLen = sprintf_s(values, 100, "%d", iFrom);
	fwrite(values, 1, iLen, f);

	fwrite("\" toChar=\"", 1, 10, f);

	iLen = sprintf_s(values, 100, "%d", iTo);
	fwrite(values, 1, iLen, f);

	fwrite("\" styles=\"", 1, 10, f);

	values[0] = 0;
	if (Style[0] == 'B') strcat_s(values, 100, "Bold ");
	if (Style[1] == 'I') strcat_s(values, 100, "Italic ");
	if (Style[2] == 'U') strcat_s(values, 100, "Underlined ");

	iLen = strlen(values);
	fwrite(iLen?values:"Normal", 1, iLen?(iLen-1):6, f);

	fwrite("\" fontID=\"1\" ", 1, 13, f);
	fwrite(cfontSize, 1, strlen(cfontSize), f);
	fwrite(" color=\"", 1, 8, f);

	iLen = sprintf_s(values, 100, "%c%c %c%c %c%c %c%c\"/>", Style[3], Style[4], Style[5], Style[6], Style[7], Style[8], Style[9], Style[10]);
	fwrite(values, 1, iLen, f);
}

void CFixTtxt::WriteStyles(FILE *f, char *Styles, int iLen, char *cfontSize)
{
	for (int i=0; i<iLen; i++) {
		int j;
		for (j=i+1; j<=iLen; j++)
			if (strcmp(Styles+i*12, Styles+j*12)) break;
		Write1Style(f, i, j, Styles+i*12, cfontSize);
		i=j-1;
	}
}

void CFixTtxt::FixIt(char *ch, int iLen, FILE *f, char *cfontSize)
{
	if (!iLen) return;
	int iNewLen;
	TCHAR *tc = tcDecode(ch, iLen, iNewLen);
	// 이제 tc에는 iNewLen 글자의 유니코드 자막 데이터가 저장되어 있음
	// 글꼴 효과 추가할 차례
	// Bold Italic Underlined 색깔
	// 이걸 char에 BIUff00ffff(NULL) 형태의 12바이트로 저장
	// 기본값은 물론 xxxffffffff

	char *chEffect = new char[(iNewLen+1)*12];

	for (int i=0; i<iNewLen; i++) {
		strcpy_s(chEffect+i*12, (iNewLen-i+1)*12, "xxxffffffff");
	}
	//이후 비교를 손쉽게 하기 위해 추가
	strcpy_s(chEffect+iNewLen*12, 12, "yyy--------");

	int iP=0;
	while (true) {
		int iBegin = iFind(ch, iLen, "<Style", iP);
		if (iBegin<0) break;

		int iEnd = iFind(ch, iLen, "/>", iBegin+6);
		if (iEnd<0) break;

		iP = iEnd+2;

		ApplyEffect(chEffect, iNewLen, ch+iBegin, iEnd-iBegin+2);
	}

	// <font> 태그 처리
	iNewLen = iFixFontTags(tc, iLen, chEffect, iNewLen);

	// &nbsp;가 갑자기 추가되는 이전 버전의 버그를 땜빵하기 위한 부분
	// 때가 되면 없앨 것임
	iNewLen = iReplaceISO8859_1Again(tc, iLen, chEffect, iNewLen);

	// 행에 남아있는 빈 줄 마지막으로 제거
	iNewLen = iRemoveNullLines(tc, iLen, chEffect, iNewLen);

	// 쓰기
	WriteXMLStr(f, tc, iNewLen);
	WriteStyles(f, chEffect, iNewLen, cfontSize);

	delete []chEffect;
	delete tc;
}


bool CFixTtxt::bFindHTMLTagRev(TCHAR *tcText, int iLen, int &iBegin, int &iEnd)
{
	// <font ~ > 같은 패턴 찾기
	bool bFound = false;
	for (iBegin=iLen-5; iBegin>=0; iBegin--) {
		if (_tcsnicmp(tcText+iBegin, _T("<FONT"), 5) == 0) {
			bFound = true;
			break;
		}
	}
	if (!bFound) return false;

	bFound = false;
	for (iEnd=iBegin+5; iEnd<iLen; iEnd++) {
		if (tcText[iEnd] == _TCHAR('>')) {
			bFound = true;
			break;
		}
	}

	if (!bFound) iEnd = iLen-1;
	return true;
}

bool CFixTtxt::bFindFONTTagClose(TCHAR *tcText, int iLen, int iFrom, int &iBegin, int &iEnd)
{
	// </font ~ > 찾기
	if (iFrom>=iLen) return false;

	bool bFound = false;
	for (iBegin=iFrom; iBegin<iLen; iBegin++) {
		if (_tcsnicmp(tcText+iBegin, _T("</FONT"), 6) == 0) {
			bFound = true;
			break;
		}
	}
	if (!bFound) return false;

	bFound = false;
	for (iEnd=iBegin+6; iEnd<iLen; iEnd++) {
		if (tcText[iEnd] == _TCHAR('>')) {
			bFound = true;
			break;
		}
	}

	if (!bFound) iEnd = iLen-1;
	return true;
}

//현재는 color 속성만 취급하지만, 앞으로 어떻게 바뀔지는 모름
int CFixTtxt::iFixFontTags(TCHAR *tcText, int buffersize, char *chProp, int iLen)
{
	while (true) {
		int iPos1, iPos2, iPos3, iPos4;
		if (!bFindHTMLTagRev(tcText, iLen, iPos1, iPos2))
			return iLen;

		bool bCloseTagExist = bFindFONTTagClose(tcText, iLen, iPos2+1, iPos3, iPos4);
		int iTo;
		if (bCloseTagExist) {
			iTo = iPos3-1;
		} else {
			iTo = iLen-1;
		}

		char *cColor = chGetColorTag(tcText+iPos1, iPos2-iPos1+1);
		if (cColor) {
			for (int i=iPos2+1; i<=iTo; i++) {
				memcpy(chProp+i*12+3, cColor, 6);
				chProp[i*12+9] = chProp[i*12+10] = 'f';
			}
			delete cColor;
		}

		////////////////////////////////////////
		//
		// 이제 태그 자체는 속성에 반영했으니
		// 속성에 반영한 태그 내용 삭제
		//
		////////////////////////////////////////
		if (bCloseTagExist) {
			iLen = iCutOut(tcText, buffersize, chProp, iLen, iPos3, iPos4);
		}
		iLen = iCutOut(tcText, buffersize, chProp, iLen, iPos1, iPos2);
	}

	return iLen;
}

// ISO8859-1을 한번 더 변환해줌. 이전의 버그 때문에 포함했으며, 언젠간 다시 없앨 예정
int CFixTtxt::iReplaceISO8859_1Again(TCHAR *tcText, int buffersize, char *chProp, int iLen)
{
	for (int i=0; i<iLen; i++) {
		TCHAR tc;
		int len;
		if (CConvISO8859_1::convOne(tcText+i, true, tc, len)) {
			// len 개의 문자열을 하나로 변환함
			// &nbsp;(6개) → ' '(1개)
			// 잘래내는 범위는 i ~ i+len-1
			// 다시 1개를 추가함
			// 즉, i+1 ~ i+len-1을 없애고, i의 값을 대체함
			iLen = iCutOut(tcText, buffersize, chProp, iLen, i+1, i+len-1);
			tcText[i] = tc;
		}
	}

	return iLen;
}

char * CFixTtxt::chGetColorTag(TCHAR *tc, int iLen)
{
	// <font color=red>
	// <font color="red">
	// <font color=#123456>
	// <font color="#123456">
	// <font color='#123456'>

	//1. color 찾기
	//2. = 찾기
	//3. 공백 스킵하기
	//4. "인가, '인가, 그냥인가

	int iBegin;
	bool bFound=false;
	for (iBegin=4; iBegin<iLen; iBegin++) {
		if (_tcsnicmp(tc+iBegin, _T("COLOR"), 5)==0) {
			bFound = true;
			break;
		}
	}
	if (!bFound) return NULL;

	for (iBegin+=5; iBegin<iLen; iBegin++) {
		if (tc[iBegin] != _TCHAR(' ')) {
			break;
		}
	}

	if (tc[iBegin] != _TCHAR('='))
		return NULL;

	for (iBegin++; iBegin<iLen; iBegin++) {
		if (tc[iBegin] != _TCHAR(' ')) {
			break;
		}
	}

	//tc[iBegin]은 드디어 태그의 시작위치를 가리킨다

	if (tc[iBegin] == _TCHAR(0))
		return NULL;

	int iEnd;
	bFound = false;

	switch (tc[iBegin]) {
	case _TCHAR('\''):
	case _TCHAR('\"'):
		{
			TCHAR quote = tc[iBegin];

			iBegin++;
			//다음 따옴표 찾아 삼만리
			for (iEnd=iBegin; iEnd<iLen; iEnd++) {
				if (tc[iEnd] == quote) {
					bFound = true;
					break;
				}
			}
		}
		break;

	default:
		{
			//글자가 중단되는 곳을 찾아야 되는데
			//공백, /, >, 컴마, 느낌표
			for (iEnd=iBegin; iEnd<iLen; iEnd++) {
				if ((tc[iEnd] == _TCHAR(' ')) ||
					(tc[iEnd] == _TCHAR('/')) ||
					(tc[iEnd] == _TCHAR('>')) ||
					(tc[iEnd] == _TCHAR(',')) ||
					(tc[iEnd] == _TCHAR('!'))) {
					bFound = true;
					break;
				}
			}
		}
	}
	if (bFound) iEnd--;
	else iEnd = iLen-1;
	
	//이제 iBegin~iEnd에 color 값이 들어있음

	char *chColor = new char[iEnd-iBegin+2];
	for (int i=0; i<(iEnd-iBegin+1); i++) {
		//색상값은 32~127 사이이므로 이거면 충분한
		chColor[i] = char(tc[iBegin+i]);
	}
	chColor[iEnd-iBegin+1] = 0;

	// *chColor에 저장된 값은 색상 코드(#123456)일 수도 있고, 색상 명칭(red)일 수도 있음
	// 이 함수의 리턴값은 색상 코드 6자리(123456)

	char *ret = chGetColorValue(chColor);
	delete []chColor;

	return ret;
}

char * CFixTtxt::chGetColorValue(char *chColor)
{
	if (chColor[0] == '#') {
		if (strlen(chColor)<7) return NULL;
		for (int i=1; i<=6; i++) {
			if (!isalnum_char(chColor[i])) return NULL;
		}
		char *ret = new char[7];
		for (int i=0; i<6; i++) {
			ret[i] = tolower(chColor[i+1]);
		}
		ret[6] = 0;
		return ret;
	} else {
		char *ch = new char[strlen(chColor)+1];
		int i=0;
		while (*chColor) {
			if ((*chColor != '\t') && (*chColor != ' '))
				ch[i++] = *chColor;
			chColor++;
		}
		ch[i] = 0;

		static char htmlcolortable[][2][21] = {
			"White",	"ffffff",
			"IndianRed",	"cd5c5c",
			"LightCoral",	"f08080",
			"Salmon",	"fa8072",
			"DarkSalmon",	"e9967a",
			"LightSalmon",	"ffa07a",
			"Crimson",	"dc143c",
			"Red",	"ff0000",
			"FireBrick",	"b22222",
			"DarkRed",	"8b0000",
			"Pink",	"ffc0cb",
			"LightPink",	"ffb6c1",
			"HotPink",	"ff69b4",
			"DeepPink",	"ff1493",
			"MediumVioletRed",	"c71585",
			"PaleVioletRed",	"db7093",
			"LightSalmon",	"ffa07a",
			"Coral",	"ff7f50",
			"Tomato",	"ff6347",
			"OrangeRed",	"ff4500",
			"DarkOrange",	"ff8c00",
			"Orange",	"ffa500",
			"Gold",	"ffd700",
			"Yellow",	"ffff00",
			"LightYellow",	"ffffe0",
			"LemonChiffon",	"fffacd",
			"LightGoldenrodYellow",	"fafad2",
			"PapayaWhip",	"ffefd5",
			"Moccasin",	"ffe4b5",
			"PeachPuff",	"ffdab9",
			"PaleGoldenrod",	"eee8aa",
			"Khaki",	"f0e68c",
			"DarkKhaki",	"bdb76b",
			"Lavender",	"e6e6fa",
			"Thistle",	"d8bfd8",
			"Plum",	"dda0dd",
			"Violet",	"ee82ee",
			"Orchid",	"da70d6",
			"Fuchsia",	"ff00ff",
			"Magenta",	"ff00ff",
			"MediumOrchid",	"ba55d3",
			"MediumPurple",	"9370db",
			"Amethyst",	"9966cc",
			"BlueViolet",	"8a2be2",
			"DarkViolet",	"9400d3",
			"DarkOrchid",	"9932cc",
			"DarkMagenta",	"8b008b",
			"Purple",	"800080",
			"Indigo",	"4b0082",
			"SlateBlue",	"6a5acd",
			"DarkSlateBlue",	"483d8b",
			"MediumSlateBlue",	"7b68ee",
			"GreenYellow",	"adff2f",
			"Chartreuse",	"7fff00",
			"LawnGreen",	"7cfc00",
			"Lime",	"00ff00",
			"LimeGreen",	"32cd32",
			"PaleGreen",	"98fb98",
			"LightGreen",	"90ee90",
			"MediumSpringGreen",	"00fa9a",
			"SpringGreen",	"00ff7f",
			"MediumSeaGreen",	"3cb371",
			"SeaGreen",	"2e8b57",
			"ForestGreen",	"228b22",
			"Green",	"008000",
			"DarkGreen",	"006400",
			"YellowGreen",	"9acd32",
			"OliveDrab",	"6b8e23",
			"Olive",	"808000",
			"DarkOliveGreen",	"556b2f",
			"MediumAquamarine",	"66cdaa",
			"DarkSeaGreen",	"8fbc8f",
			"LightSeaGreen",	"20b2aa",
			"DarkCyan",	"008b8b",
			"Teal",	"008080",
			"Aqua",	"00ffff",
			"Cyan",	"00ffff",
			"LightCyan",	"e0ffff",
			"PaleTurquoise",	"afeeee",
			"Aquamarine",	"7fffd4",
			"Turquoise",	"40e0d0",
			"MediumTurquoise",	"48d1cc",
			"DarkTurquoise",	"00ced1",
			"CadetBlue",	"5f9ea0",
			"SteelBlue",	"4682b4",
			"LightSteelBlue",	"b0c4de",
			"PowderBlue",	"b0e0e6",
			"LightBlue",	"add8e6",
			"SkyBlue",	"87ceeb",
			"LightSkyBlue",	"87cefa",
			"DeepSkyBlue",	"00bfff",
			"DodgerBlue",	"1e90ff",
			"CornflowerBlue",	"6495ed",
			"MediumSlateBlue",	"7b68ee",
			"RoyalBlue",	"4169e1",
			"Blue",	"0000ff",
			"MediumBlue",	"0000cd",
			"DarkBlue",	"00008b",
			"Navy",	"000080",
			"MidnightBlue",	"191970",
			"Cornsilk",	"fff8dc",
			"BlanchedAlmond",	"ffebcd",
			"Bisque",	"ffe4c4",
			"NavajoWhite",	"ffdead",
			"Wheat",	"f5deb3",
			"BurlyWood",	"deb887",
			"Tan",	"d2b48c",
			"RosyBrown",	"bc8f8f",
			"SandyBrown",	"f4a460",
			"Goldenrod",	"daa520",
			"DarkGoldenrod",	"b8860b",
			"Peru",	"cd853f",
			"Chocolate",	"d2691e",
			"SaddleBrown",	"8b4513",
			"Sienna",	"a0522d",
			"Brown",	"a52a2a",
			"Maroon",	"800000",
			"White",	"ffffff",
			"Snow",	"fffafa",
			"Honeydew",	"f0fff0",
			"MintCream",	"f5fffa",
			"Azure",	"f0ffff",
			"AliceBlue",	"f0f8ff",
			"GhostWhite",	"f8f8ff",
			"WhiteSmoke",	"f5f5f5",
			"Seashell",	"fff5ee",
			"Beige",	"f5f5dc",
			"OldLace",	"fdf5e6",
			"FloralWhite",	"fffaf0",
			"Ivory",	"fffff0",
			"AntiqueWhite",	"faebd7",
			"Linen",	"faf0e6",
			"LavenderBlush",	"fff0f5",
			"MistyRose",	"ffe4e1",
			"Gainsboro",	"dcdcdc",
			"LightGrey",	"d3d3d3",
			"Silver",	"c0c0c0",
			"DarkGray",	"a9a9a9",
			"Gray",	"808080",
			"DimGray",	"696969",
			"LightSlateGray",	"778899",
			"SlateGray",	"708090",
			"DarkSlateGray",	"2f4f4f",
			"Black",	"000000"
		};

		int iTotal = sizeof(htmlcolortable) / sizeof(htmlcolortable[0]);

		for (i=0; i<iTotal; i++) {
			if (_stricmp(htmlcolortable[i][0], ch) == 0) {
				char *ret = new char[7];
				strcpy_s(ret, 7, htmlcolortable[i][1]);
				{
					delete []ch;
					return ret;
				}
			}
		}

		// 다 확인했는데, 적합한 색상이 없을 때는
		// 0~9, A-F, a-f 만 추려서 색상으로 사용할 수 있는지 확인
		// 멍청하게 #123456 대신 123456으로 지정하는 바보들을 위한 옵션

		iTotal = strlen(ch);
		char *ret = new char[iTotal+1];

		int iNewLen=0;
		for (i=0; i<iTotal; i++) {
			if (isalnum_char(ch[i]))
				ret[iNewLen++] = tolower(ch[i]);
		}
		if (iNewLen>=6) {
			ret[6] = 0;
			delete []ch;
			return ret;
		}

		delete []ret;
		delete []ch;
		return NULL;
	}
}

int CFixTtxt::iCutOut(TCHAR *tcText, int buffersize, char *chProp, int iLen, int iP1, int iP2)
{
	// iLen 개의 데이터(0~iLen-1)에서 iP1~iP2를 제거하는 함수
	// iP2 이후부터 iP1에 복사하는 구조이며,
	// 복사하는 갯수는 iLen-iP2

	// 주의할 점은 chProp는 데이터가 iLen개가 아니라 iLen+1개라는 것

	//*tcText는 iP2가 iLen-1보다 작을 때만 복사

	if (iP2 < iLen-1) {
		_tcsncpy_s(tcText+iP1, buffersize-iP1, tcText+iP2+1, iLen-iP2);
		memcpy(chProp+iP1*12, chProp+(iP2+1)*12, (iLen-iP2+1)*12);
		return iLen-(iP2-iP1+1);
	} else if (iP2 == iLen-1) {
		memcpy(chProp+iP1*12, chProp+iLen*12, 12);
		return iP1;
	}
	return iLen;
}

int CFixTtxt::iRemoveNullLines(TCHAR *tcText, int buffersize, char *chProp, int iLen)
{
	int iPos=0;
	int iBegin=0;
	int iLineLen=0;
	bool bFound = false;

	while (iPos<iLen) {
		// 0x0d는 없고, 0x0a만 있다는 걸 기억할 것
		if (tcText[iPos] == _TCHAR(0x0a)) {
			//읽다보니 엔터를 만났음
			if (iLineLen==0) {
				//내용이 전혀 없는, 엔터만 있는 라인
				iLen = iCutOut(tcText, buffersize, chProp, iLen, iPos, iPos);
				iBegin = iPos;
				continue;
			}

			if (!bFound) {
				//줄에 공백 외의 문자가 하나도 없을 때
				iLen = iCutOut(tcText, buffersize, chProp, iLen, iBegin, iPos);
				iPos = iBegin;
				continue;
			}

			//정상적인 줄
			iPos++;
			iBegin = iPos;
			bFound = false;
			iLineLen = 0;
			continue;
		}

		if (tcText[iPos] != _TCHAR(' ')) {
			bFound = true;
		}
		iLineLen++;

		if (iPos == (iLen-1)) {
			//텍스트 맨 마지막, 엔터와는 좀 다르게 동작
			if (iLineLen==0) {
				//마지막인데, 엔터가 없음 -> 이런 경우는 없음
				break;
			}
			if (!bFound) {
				//줄에 공백 외의 문자가 하나도 없을 때
				iLen = iCutOut(tcText, buffersize, chProp, iLen, iBegin, iPos);
				break;
			}
		}

		iPos++;
	}

	if (iLen && (tcText[iLen-1]==_TCHAR(0x0a))) {
		//맨 마지막이 엔터인 거의 발생할 수 없는 메롱같은 경우
		iLen = iCutOut(tcText, buffersize, chProp, iLen, iLen-1, iLen-1);
	}

	return iLen;
}
